#pragma once

#include "IOUringDefs.h"
#include "InetAddress.h"
#include "Noncopyable.h"
#include <functional>
#include <liburing.h>

class IOUringEventLoop;
class IOUring : Noncopyable {
  public:
    using NewConnectionCallback = std::function<void(struct io_uring_cqe *cqe)>;
    using WriteCompleteCallback = std::function<void(struct io_uring_cqe *cqe)>;
    using ReadCompleteCallback = std::function<void(struct io_uring_cqe *cqe)>;

    IOUring(int entries, int groupId, IOUringEventLoop *loop);
    void addProvideBuf(uint16_t bid);
    void addAccept(int fd, InetAddress &peerAddr, unsigned flags);
    void addRead(int fd, size_t size, uint32_t flags);
    void addWrite(int fd, uint16_t bid, size_t size, uint32_t flags);
    void addProvideBufAll();

    void handleCqes();

    void setNewConnectionCallback(NewConnectionCallback cb) {
        newConnectionCallback_ = std::move(cb);
    }
    void setWriteCompleteCallback(WriteCompleteCallback cb) {
        writeCompleteCallback_ = std::move(cb);
    }
    void setReadCompleteCallback(ReadCompleteCallback cb) {
        readCompleteCallback_ = std::move(cb);
    }

    struct io_uring *ring();
    char *buf(int bid) { return bufs_[bid]; }

  public:
    static const int kBuffersCount = 4096;
    static const int kMaxMessageLen = 1024 + 8;

  private:
    enum {
        ACCEPT,
        READ,
        WRITE,
        PROV_BUF,
    };

    struct io_uring ring_;
    IOUringEventLoop *loop_;

    char bufs_[kBuffersCount][kMaxMessageLen];
    int groupId_;
    int entries_;
    NewConnectionCallback newConnectionCallback_;
    WriteCompleteCallback writeCompleteCallback_;
    ReadCompleteCallback readCompleteCallback_;
}; // class IOUring
